home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / ftpcli.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  39KB  |  1,613 lines

  1. /*
  2.     Internet FTP client (interactive user)
  3.    Copyright 1991 Phil Karn, KA9Q
  4. */
  5.  
  6. /* Modified by paul@wolf.demon.co.uk to support a local 'view' command */
  7.  
  8. /****************************************************************************
  9. *    $Id: ftpcli.c 1.8 94/02/02 14:37:51 ROOT_DOS Exp $
  10. *    13 Sep 92    1.4        GT    Log "cd", "get" and "mget" commands.
  11. *    08 May 93    1.5        GT    Fix warnings.                                
  12. *    22 Dec 93    1.6        iain@nomed.demon.co.uk    Batch stuff.    
  13. *    24 Jan 94    1.7        GT    Fix batch file type setting.            
  14. *    01 Feb 94    1.8        GT    "ftpopt" command.                            
  15. *
  16. *  Atari Version by David Nash - dnash@chaos.demon.co.uk
  17. *
  18. *  26.08.93 - Add CDUP command
  19. *             Add dobytes, do_opt_bytes to add bytes verbosity level
  20. *
  21. ****************************************************************************/
  22.  
  23. /***************************************************************************
  24.  *    Modified by Iain Douglas ( iain@nomed.demon.co.uk 21/12/1993            *
  25.  * Added source <filename>     to redirect input from a file                *
  26.  * Added close to allow users to close connection to current host without  *
  27.  *             having to leave current session.                            *
  28.  * Added open <host> to allow users to open connection to new hosts        *
  29.  * Extensivly remodeled the main loop to allow for opening and closing     *
  30.  * connections to hosts and scripted command files.                        *
  31.  ***********************************************************************ID**/
  32.  
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include <errno.h>                                    /* ATARI: sys_errlist > strerror*/
  36. #include "global.h"
  37. #include "files.h"
  38. #include "mbuf.h"
  39. #include "session.h"
  40. #include "cmdparse.h"
  41. #include "proc.h"
  42. #include "tty.h"
  43. #include "socket.h"
  44. #include "ftp.h"
  45. #include "ftpcli.h"
  46. #include "commands.h"
  47. #include "netuser.h"
  48. #include "dirutil.h"
  49. #include "help.h"
  50.  
  51. #define    DIRBUF    256
  52.  
  53. static int doascii __ARGS((int argc,char *argv[],void *p));
  54. static int dobatch __ARGS((int argc,char *argv[],void *p));
  55. static int dobinary __ARGS((int argc,char *argv[],void *p));
  56. static int dobytes __ARGS((int argc,char *argv[],void *p));
  57. static int doftpcd __ARGS((int argc,char *argv[],void *p));
  58. static int doftpcdup __ARGS((int argc,char *argv[],void *p));
  59. static int doget __ARGS((int argc,char *argv[],void *p));
  60. static int dohash __ARGS((int argc,char *argv[],void *p));
  61. static int doftphelp __ARGS((int argc,char *argv[],void *p));
  62. static int doverbose __ARGS((int argc,char *argv[],void *p));
  63. static int dolist __ARGS((int argc,char *argv[],void *p));
  64. static int dols __ARGS((int argc,char *argv[],void *p));
  65. static int domkdir __ARGS((int argc,char *argv[],void *p));
  66. static int domget __ARGS((int argc,char *argv[],void *p));
  67. static int domput __ARGS((int argc,char *argv[],void *p));
  68. static int dopager __ARGS((int argc,char *argv[],void *p));
  69. static int doput __ARGS((int argc,char *argv[],void *p));
  70. static int doquit __ARGS((int argc,char *argv[],void *p));
  71. static int dormdir __ARGS((int argc,char *argv[],void *p));
  72. static int dotype __ARGS((int argc,char *argv[],void *p));
  73. static int doview __ARGS((int argc,char *argv[],void *p));
  74. static int getline __ARGS((struct session *sp,char *prompt,char *buf,int n));
  75. static int getresp __ARGS((struct ftpcli *ftp,int mincode));
  76. static long getsub __ARGS((struct ftpcli *ftp,char *command,char *remotename,
  77.     char *localname));
  78. static long putsub __ARGS((struct ftpcli *ftp,char *remotename,char *localname));
  79. static void sendport __ARGS((int s,struct sockaddr_in *socket));
  80.  
  81. static int dosource __ARGS((int argc, char *argv[], void *p));
  82. static int doopen __ARGS((int argc, char *argv[],void *p));
  83. static int doclose __ARGS(( int argc, char *argv[], void *p));
  84. static void init_ftpstruct(struct session *sp,struct ftpcli *ftp,
  85.                   struct sockaddr_in *fsocket);
  86. static void sourceline(struct session *sp,char *prompt,char *buf,int n);
  87.  
  88. static int do_opt_verbose __ARGS((int argc, char *argv[], void *p));
  89. static int do_opt_bytes __ARGS((int argc, char *argv[], void *p));
  90. static int do_opt_hash __ARGS((int argc, char *argv[], void *p));
  91. static int do_opt_type __ARGS((int argc, char *argv[], void *p));
  92. static int do_opt_ascii __ARGS((int argc, char *argv[], void *p));
  93. static int do_opt_binary __ARGS((int argc, char *argv[], void *p));
  94. static int do_opt_pager __ARGS((int argc, char *argv[], void *p));
  95. static int do_opt_wrap __ARGS((int argc, char *argv[], void *p));
  96. static void set_default_opts __ARGS((struct ftpcli *ftp));
  97.  
  98. #define NOTCONNECTED -2
  99. #define REALLYQUIT -3
  100.  
  101. static char dummyhost[]="nohost.nowhere.nocom";
  102. static char Notsess[] = "Not an FTP session!\n";
  103.  
  104. /* FTP options default settings. */
  105.  
  106. static int16 verbose = V_NORMAL;                    /* report verbosity                */
  107. static char type         = ASCII_TYPE;                /* transfer type                    */
  108. static int logbsize     = 0;                            /* logical byte size                */
  109. static int pager         = 0;                            /* nz - paging on                    */
  110. static int16 wrap     = 0;                            /* hash wrap column                */
  111.  
  112.  
  113. static struct cmds Ftpcmds[] = {
  114.     { "",            donothing,    0, 0, NULLCHAR },
  115.     { "ascii",    doascii,        0, 0, NULLCHAR },
  116.     { "batch",    dobatch,        0, 0, NULLCHAR },
  117.     { "binary",    dobinary,    0, 0, NULLCHAR },
  118.     { "bytes",    dobytes,        0, 0, NULLCHAR },
  119.     { "cd",        doftpcd,        0, 2, "cd <directory>" },
  120.     { "cdup",    doftpcdup,    0,    0, NULLCHAR },
  121.     { "close",    doclose,        0, 0, NULLCHAR },
  122.     { "dir",        dolist,        0, 0, NULLCHAR },
  123.     { "list",    dolist,        0, 0, NULLCHAR },
  124.     { "get",        doget,        0, 2, "get <remotefile> <localfile>" },
  125.     { "hash",    dohash,        0, 0, NULLCHAR },
  126.     { "help",   doftphelp,  0, 0, NULLCHAR },
  127.     { "ls",        dols,            0, 0, NULLCHAR },
  128.     { "mget",    domget,        0, 2, "mget <file> [<file> ...]" },
  129.     { "mkdir",  domkdir,     0, 2, "mkdir <directory>" },
  130.     { "mput",    domput,        0, 2, "mput <file> [<file> ...]" },
  131.     { "open",    doopen,     0, 2, "open <host>"},
  132.     { "nlst",    dols,            0, 0, NULLCHAR },
  133.     { "pager",  dopager,    0, 0, NULLCHAR },
  134.     { "quit",    doquit,        0, 0, NULLCHAR },
  135.     { "rmdir",    dormdir,        0, 2, "rmdir <directory>" },
  136.     { "put",        doput,        0, 2, "put <localfile> <remotefile>" },
  137.     { "source", dosource,   0, 2, "source <filename>" },
  138.     { "type",    dotype,        0, 0, NULLCHAR },
  139.     { "verbose",doverbose,    0, 0, NULLCHAR },
  140.     { "view",   doview,     0, 2, "view <remotefile>" },
  141.     { NULLCHAR,    NULLFP,        0, 0, NULLCHAR },
  142. };
  143.  
  144. static struct cmds ftp_opt_cmds[] =
  145.     {
  146.         { "",                donothing,            0,    0,    NULLCHAR },
  147.         { "verbose",    do_opt_verbose,    0,    0,    NULLCHAR },
  148.         { "bytes",        do_opt_bytes,        0,    0,    NULLCHAR },
  149.         { "hash",        do_opt_hash,        0,    0,    NULLCHAR },
  150.         { "type",        do_opt_type,        0,    0,    NULLCHAR },
  151.         { "ascii",        do_opt_ascii,        0,    0,    NULLCHAR },
  152.         { "binary",        do_opt_binary,        0,    0,    NULLCHAR },
  153.         { "pager",        do_opt_pager,        0,    0,    NULLCHAR },
  154.         { "wrap",        do_opt_wrap,        0,    0,    NULLCHAR },
  155.         { NULLCHAR,        NULLFP,                0,    0,    NULLCHAR }
  156.     };
  157.         
  158.  
  159. /*
  160.     doftp - Handle top-level FTP command
  161. */
  162.  
  163. int __stdargs doftp(int argc, char *argv[], void *p)
  164. {
  165.     struct session *sp;
  166.     struct ftpcli ftp;
  167.     struct sockaddr_in fsocket;
  168.     int resp,vsave;
  169.     char *buf,*bufsav,*cp,*tmp;
  170.     int control,controlsave=NOTCONNECTED;
  171.  
  172.  
  173.      /* Allocate a session control block  and init the ftp struct*/
  174.      if(argc >1)
  175.       tmp = argv[1];
  176.      else
  177.       tmp = dummyhost;
  178.  
  179.      if((sp = newsession(tmp,FTP)) == NULLSESSION)
  180.       {
  181.        tprintf("Too Many Sessions\n");
  182.        return 1;
  183.       }
  184.  
  185.      init_ftpstruct(sp,&ftp,&fsocket);
  186.  
  187.      resp=200;                 /* dummy resp and control values   */
  188.      control= NOTCONNECTED;    /* to get into the main loop if    */
  189.                      /* no host passed on the cmd line  */
  190.  
  191.      if(argc >1)               /* if there is a cmd line param    */
  192.       {                      /* attempt to connect to host      */
  193.        if((resp=doopen( argc, argv, &ftp))==1)
  194.         goto quit;         /* only if there is a problem with */
  195.                      /* the socket                      */
  196.        control=ftp.control;
  197.       }
  198.  
  199.     /* Now process responses and commands */
  200.     buf = mallocw(LINELEN);
  201.  
  202.     while(resp != -1)
  203.        {
  204.         if(resp == 220)
  205.          {
  206.           /* Sign-on banner; prompt for and send USER command */
  207.               if(ftp.sourcefileon==1)
  208.               sourceline(sp,"Enter user name: ",buf,LINELEN);
  209.           else
  210.           getline(sp,"Enter user name: ",buf,LINELEN);
  211.  
  212.           /* Send the command only if the user response was non-null */
  213.  
  214.           if(buf[0] != '\n')
  215.              {
  216.             usprintf(control,"USER %s",buf);
  217.             resp = getresp(&ftp,200);
  218.              }
  219.           else
  220.             resp = 200;    /* dummy */
  221.          }
  222.         else
  223.          if(resp == 331)
  224.             {
  225.              sp->ttystate.echo = 0;  /* turn off echo */
  226.                  if(ftp.sourcefileon==1)
  227.               sourceline(sp,"Password: ",buf,LINELEN);
  228.              else
  229.               getline(sp,"Password: ",buf,LINELEN);
  230.              tprintf("\n");
  231.              sp->ttystate.echo = 1; /* Turn echo back on */
  232.              /* Send the command only if the user response was non-null */
  233.              if(buf[0] != '\n')
  234.               {
  235.                usprintf(control,"PASS %s",buf);
  236.                resp = getresp(&ftp,200);
  237.               }
  238.              else
  239.                resp = 200;    /* dummy */
  240.            }
  241.          else
  242.             {
  243.              if(control != NOTCONNECTED) /* Test the control channel first */
  244.               {
  245.                if(sockstate(control) == NULLCHAR)
  246.                  break;
  247.               }
  248.  
  249.              if(ftp.sourcefileon==1)
  250.               sourceline(sp,"ftp> ",buf,LINELEN);
  251.              else
  252.               getline(sp,"ftp> ",buf,LINELEN);
  253.  
  254.              /* Copy because cmdparse modifies the original */
  255.              bufsav = strdup(buf);
  256.              if((resp = cmdparse(Ftpcmds,buf,&ftp)) != -1)
  257.               {
  258.                free(bufsav); /* Valid command, free buffer */
  259.  
  260.                if( resp == REALLYQUIT) /* if last command was quit */
  261.                  resp = - 1;         /* then flag quit           */
  262.                else
  263.                 {
  264.                  if(ftp.control== NOTCONNECTED)
  265.                     {
  266.                      tprintf("WARNING you are not connected to a remote host\n");
  267.                      control=NOTCONNECTED;
  268.                     }
  269.                  else
  270.                     {
  271.                      control=ftp.control; /* remote connect established */
  272.                      if(controlsave==0)   /* save info for use when quit*/
  273.                       controlsave=control; /* requested */
  274.                     }
  275.                 }
  276.               }
  277.              else
  278.               {
  279.                /* if no connection to remote host exists then don't  */
  280.                /* attempt to send the command to it. Assume it was a */
  281.                /* user typo as, usputs() returns -1 if it fails and  */
  282.                /* this causes  the session to quit.                  */
  283.  
  284.                if(ftp.control != NOTCONNECTED)
  285.                 {
  286.                  /* Not a local cmd, or user typo send to remote server */
  287.                  usputs(control,bufsav);
  288.                  free(bufsav);
  289.  
  290.                  /* Enable display of server response */
  291.                  vsave = ftp.verbose;
  292.                  ftp.verbose = V_NORMAL;
  293.                  resp = getresp(&ftp,200);
  294.                  ftp.verbose = vsave;
  295.                 }
  296.                else
  297.                 resp = 200;
  298.               }
  299.         }
  300.     }
  301.      free(buf);
  302.      /* if the user issued a close command before quit then restore the */
  303.      /* value of control so that sockerr gives the right message.       */
  304.      if(control == NOTCONNECTED)
  305.        control=controlsave;
  306.  
  307. quit:    if(controlsave != NOTCONNECTED)
  308.         cp = sockerr(control);
  309.     else
  310.        cp=NULLCHAR;
  311.  
  312.     tprintf("FTP session %u closed: %s\n",(unsigned)(sp - Sessions),
  313.      cp != NULLCHAR ? cp : "EOF");
  314.  
  315.     if(ftp.fp != NULLFILE && ftp.fp != stdout)
  316.         fclose(ftp.fp);
  317.     if(ftp.data != -1)
  318.         close_s(ftp.data);
  319.     if(ftp.control != -1)
  320.         close_s(ftp.control);
  321.     keywait(NULLCHAR,1);
  322.     if(ftp.session != NULLSESSION)
  323.         freesession(ftp.session);
  324.     return 0;
  325. }
  326.  
  327.  
  328. /****************************************************************************
  329. *    doftpopt            
  330. *    Process default ftp options.
  331. ****************************************************************************/
  332.  
  333. int doftpopt (argc, argv, p)
  334. int argc;
  335. char *argv[];
  336. void *p;
  337.     {
  338.     return (subcmd (ftp_opt_cmds, argc, argv, p));
  339.     }    /* int doftpopt (argc, argv, p) */
  340.  
  341. /****************************************************************************
  342. *    ftp default option processing functions.                                *
  343. ****************************************************************************/
  344.  
  345. static int do_opt_verbose (argc, argv, p)
  346. int argc;
  347. char *argv[];
  348. void *p;
  349.     {
  350.     return (setshort (&verbose, "Verbose", argc, argv));
  351.     }    /* static int do_opt_verbose (argc, argv, p) */
  352.  
  353.  
  354. static int do_opt_hash (argc, argv, p)
  355. int argc;
  356. char *argv[];
  357. void *p;
  358.     {
  359.     verbose = V_HASH;
  360.     return (0);
  361.     }    /* static int do_opt_hash (argc, argv, p) */
  362.  
  363. static int do_opt_bytes(int argc, char *argv[], void *p)
  364. {
  365.     verbose = V_BYTE;
  366.     return 0;
  367. }
  368.  
  369. static int do_opt_type (argc, argv, p)
  370. int argc;
  371. char *argv[];
  372. void *p;
  373.     {
  374.     if (argc < 2)
  375.         {
  376.         switch (type)
  377.             {
  378.             case IMAGE_TYPE:
  379.                 tprintf("Image\n");
  380.                 break;
  381.                 
  382.             case ASCII_TYPE:
  383.                 tprintf("Ascii\n");
  384.                 break;
  385.                 
  386.             case LOGICAL_TYPE:
  387.                 tprintf("Logical bytesize %u\n", logbsize);
  388.                 break;
  389.             }    /* switch (type) */
  390.             
  391.         return 0;
  392.         }    /* if (argc < 2) */
  393.         
  394.     switch (*argv[1])
  395.         {
  396.         case 'i':
  397.         case 'I':
  398.         case 'b':
  399.         case 'B':
  400.             type = IMAGE_TYPE;
  401.             break;
  402.             
  403.         case 'a':
  404.         case 'A':
  405.             type = ASCII_TYPE;
  406.             break;
  407.             
  408.         case 'L':
  409.         case 'l':
  410.             type = LOGICAL_TYPE;
  411.             logbsize = atoi(argv[2]);
  412.             break;
  413.  
  414.         default:
  415.             tprintf("Invalid type %s\n",argv[1]);
  416.             return 1;
  417.         }    /* switch (*argv[1]) */
  418.         
  419.     return 0;
  420.     }    /* static int do_opt_type (argc, argv, p) */
  421.  
  422.  
  423. static int do_opt_binary (argc, argv, p)
  424. int argc;
  425. char *argv[];
  426. void *p;
  427.     {
  428.     char *args[2];
  429.  
  430.     args[1] = "I";
  431.     return do_opt_type (2, args, p);
  432.     }    /* static int do_opt_binary (argc, argv, p) */
  433.  
  434.  
  435. static int do_opt_ascii (argc, argv, p)
  436. int argc;
  437. char *argv[];
  438. void *p;
  439.     {
  440.     char *args[2];
  441.  
  442.     args[1] = "A";
  443.     return do_opt_type (2, args, p);
  444.     }    /* static int do_opt_ascii (argc, argv, p) */
  445.  
  446.  
  447. static int do_opt_pager (argc, argv, p)
  448. int argc;
  449. char *argv[];
  450. void *p;
  451.     {
  452.     return (setbool (&pager, "Pager", argc, argv));
  453.     }    /* static int do_opt_pager (argc, argv, p) */
  454.  
  455.  
  456. static int do_opt_wrap (argc, argv, p)
  457. int argc;
  458. char *argv[];
  459. void *p;
  460.     {
  461.     return (setshort (&wrap, "Wrap column", argc, argv));
  462.     }    /* static int do_opt_wrap (argc, argv, p) */
  463.     
  464.  
  465. /* Control verbosity level */
  466. static int
  467. doverbose(argc,argv,p)
  468. int argc;
  469. char *argv[];
  470. void *p;
  471. {
  472.     register struct ftpcli *ftp;
  473.  
  474.     if((ftp = (struct ftpcli *)p) == NULLFTP)
  475.         return -1;
  476.     return setshort(&ftp->verbose,"Verbose",argc,argv);
  477. }
  478. /* Enable/disable command batching */
  479. static int
  480. dobatch(argc,argv,p)
  481. int argc;
  482. char *argv[];
  483. void *p;
  484. {
  485.     register struct ftpcli *ftp;
  486.  
  487.     if((ftp = (struct ftpcli *)p) == NULLFTP)
  488.         return -1;
  489.     return setbool(&ftp->batch,"Command batching",argc,argv);
  490. }
  491. /* Set verbosity to high (convenience command) */
  492. static int
  493. dohash(argc,argv,p)
  494. int argc;
  495. char *argv[];
  496. void *p;
  497. {
  498.     register struct ftpcli *ftp;
  499.  
  500.     if((ftp = (struct ftpcli *)p) == NULLFTP)
  501.         return -1;
  502.     ftp->verbose = V_HASH;
  503.     return 0;
  504. }
  505.  
  506. /*
  507.     dobytes - Set verbosity to high (convenience command)
  508. */
  509.  
  510. static int dobytes(int argc, char *argv[], void *p)
  511. {
  512.     struct ftpcli *ftp;
  513.  
  514.     if((ftp = (struct ftpcli *)p) == NULLFTP)
  515.         return -1;
  516.  
  517.     ftp->verbose = V_BYTE;
  518.     return 0;
  519. }
  520.  
  521. /* Simple help display - displays all commands and parameters */
  522. static int
  523. doftphelp(argc,argv,p)
  524. int argc;
  525. char *argv[];
  526. void *p;
  527. {
  528.     char buf[256];
  529.     sprintf(buf,"%s/ftp.hlp",Helpdir);
  530.     helproutine(argc,argv,Ftpcmds,buf);
  531.     return 0;
  532. }
  533.  
  534. /* Close session */
  535. static int
  536. doquit(argc,argv,p)
  537. int argc;
  538. char *argv[];
  539. void *p;
  540. {
  541.     register struct ftpcli *ftp;
  542.  
  543.     ftp = (struct ftpcli *)p;
  544.     if(ftp == NULLFTP)
  545.         return -1;
  546.     usprintf(ftp->control,"QUIT\n");
  547.     getresp(ftp,200);    /* Get the closing message */
  548.     getresp(ftp,200);    /* Wait for the server to close */
  549.     return -3;
  550. }
  551.  
  552. /* Translate 'cd' to 'cwd' for convenience */
  553. static int
  554. doftpcd(argc,argv,p)
  555. int argc;
  556. char *argv[];
  557. void *p;
  558. {
  559.     register struct ftpcli *ftp;
  560.  
  561.     ftp = (struct ftpcli *)p;
  562.     if(ftp == NULLFTP)
  563.         return -1;
  564.     usprintf(ftp->control,"CWD %s\n",argv[1]);
  565.     log (ftp->control, "FTP %s: CWD %s", ftp->session->name, argv[1]);
  566.     return getresp(ftp,200);
  567. }
  568.  
  569. /*
  570.     doftpcdup - Translate 'cdup' to 'CDUP' for convenience
  571. */
  572.  
  573. static int doftpcdup(int argc, char *argv[], void *p)
  574. {
  575.     struct ftpcli *ftp;
  576.  
  577.     ftp = (struct ftpcli *)p;
  578.  
  579.     if (ftp == NULLFTP)
  580.          return -1;
  581.  
  582.      usprintf(ftp->control,"CDUP\n",argv[1]);
  583.      log(ftp->control, "FTP %s: CDUP ", ftp->session->name, argv[1]);
  584.  
  585.      return getresp(ftp, 200);
  586. }
  587.  
  588. /* Translate 'mkdir' to 'xmkd' for convenience */
  589. static int
  590. domkdir(argc,argv,p)
  591. int argc;
  592. char *argv[];
  593. void *p;
  594. {
  595.     register struct ftpcli *ftp;
  596.  
  597.     ftp = (struct ftpcli *)p;
  598.     if(ftp == NULLFTP)
  599.         return -1;
  600.     usprintf(ftp->control,"XMKD %s\n",argv[1]);
  601.     return getresp(ftp,200);
  602. }
  603. /* Translate 'rmdir' to 'xrmd' for convenience */
  604. static int
  605. dormdir(argc,argv,p)
  606. int argc;
  607. char *argv[];
  608. void *p;
  609. {
  610.     register struct ftpcli *ftp;
  611.  
  612.     ftp = (struct ftpcli *)p;
  613.     if(ftp == NULLFTP)
  614.         return -1;
  615.     usprintf(ftp->control,"XRMD %s\n",argv[1]);
  616.     return getresp(ftp,200);
  617. }
  618. static int
  619. dobinary(argc,argv,p)
  620. int argc;
  621. char *argv[];
  622. void *p;
  623. {
  624.     char *args[2];
  625.  
  626.     args[1] = "I";
  627.     return dotype(2,args,p);
  628. }
  629. static int
  630. doascii(argc,argv,p)
  631. int argc;
  632. char *argv[];
  633. void *p;
  634. {
  635.     char *args[2];
  636.  
  637.     args[1] = "A";
  638.     return dotype(2,args,p);
  639. }
  640.  
  641. /* Handle "type" command from user */
  642. static int
  643. dotype(argc,argv,p)
  644. int argc;
  645. char *argv[];
  646. void *p;
  647. {
  648.     register struct ftpcli *ftp;
  649.  
  650.     ftp = (struct ftpcli *)p;
  651.     if(ftp == NULLFTP)
  652.         return -1;
  653.     if(argc < 2){
  654.         switch(ftp->type){
  655.         case IMAGE_TYPE:
  656.             tprintf("Image\n");
  657.             break;
  658.         case ASCII_TYPE:
  659.             tprintf("Ascii\n");
  660.             break;
  661.         case LOGICAL_TYPE:
  662.             tprintf("Logical bytesize %u\n",ftp->logbsize);
  663.             break;
  664.         }
  665.         return 0;
  666.     }
  667.     switch(*argv[1]){
  668.     case 'i':
  669.     case 'I':
  670.     case 'b':
  671.     case 'B':
  672.         ftp->type = IMAGE_TYPE;
  673.         break;
  674.     case 'a':
  675.     case 'A':
  676.         ftp->type = ASCII_TYPE;
  677.         break;
  678.     case 'L':
  679.     case 'l':
  680.         ftp->type = LOGICAL_TYPE;
  681.         ftp->logbsize = atoi(argv[2]);
  682.         break;
  683.     default:
  684.         tprintf("Invalid type %s\n",argv[1]);
  685.         return 1;
  686.     }
  687.     return 0;
  688. }
  689.  
  690. /* Handle "pager" command from user */
  691. static int
  692. dopager(argc,argv,p)
  693. int argc;
  694. char *argv[];
  695. void *p;
  696. {
  697.     register struct ftpcli *ftp;
  698.     struct session *s;
  699.  
  700.     ftp=(struct ftpcli *)p;
  701.     s=ftp->session;
  702.  
  703.     if (ftp==NULLFTP){
  704.         tprintf(Notsess);
  705.         return 1;
  706.     }
  707.  
  708.     return setbool(&s->flowmode,"Pager",argc,argv);
  709. }
  710.  
  711. /* Start view transfer. Syntax: view <remote name>  */
  712. static int
  713. doview(argc,argv,p)
  714. int argc;
  715. char *argv[];
  716. void *p;
  717. {
  718.     char *remotename;
  719.     register struct ftpcli *ftp;
  720.  
  721.     ftp = (struct ftpcli *)p;
  722.     if(ftp == NULLFTP){
  723.         tprintf(Notsess);
  724.         return 1;
  725.     }
  726.     remotename = argv[1];
  727.  
  728.     getsub(ftp,"RETR",remotename,NULLCHAR);
  729.     return 0;
  730. }
  731.  
  732. /* Start receive transfer. Syntax: get <remote name> [<local name>] */
  733. static int
  734. doget(argc,argv,p)
  735. int argc;
  736. char *argv[];
  737. void *p;
  738. {
  739.     char *remotename,*localname;
  740.     register struct ftpcli *ftp;
  741.  
  742.     ftp = (struct ftpcli *)p;
  743.     if(ftp == NULLFTP){
  744.         tprintf(Notsess);
  745.         return 1;
  746.     }
  747.     remotename = argv[1];
  748.     if(argc < 3)
  749.         localname = remotename;
  750.     else
  751.         localname = argv[2];
  752.  
  753.     getsub(ftp,"RETR",remotename,localname);
  754.     return 0;
  755. }
  756.  
  757.  
  758. /*
  759.     mget - Get a collection of files
  760. */
  761.  
  762. static int domget(int argc, char *argv[], void *p)
  763. {
  764.     int i;
  765.     long r;
  766.     char *buf;
  767.      char tmpname[L_tmpnam+1];
  768.     FILE *files;
  769.     struct ftpcli *ftp;
  770.  
  771.     if ((ftp = (struct ftpcli *)p) == NULLFTP) {
  772.         tprintf(Notsess);
  773.         return 1;
  774.     }
  775.     
  776.     tmpnam(tmpname);
  777.  
  778.     buf = mallocw(DIRBUF);
  779.  
  780.     ftp->state = RECEIVING_STATE;
  781.  
  782.     for (i=1 ; i < argc; i++) {
  783.         r = getsub(ftp, "NLST", argv[i], tmpname);    /* get list of names    */
  784.         if (ftp->abort)
  785.             break;                                            /* Aborted                         */
  786.  
  787.         if (r == -1 || (files = fopen(tmpname,"r")) == NULLFILE) {
  788.             tprintf("Can't NLST %s\n", argv[i]);
  789.             unlink(tmpname);
  790.             continue;
  791.         }
  792.         
  793.     /*
  794.         The tmp file now contains a list of the remote files, so go get 'em.
  795.         Break out if the user signals an abort.
  796.     */
  797.         while (fgets(buf, DIRBUF, files) != NULLCHAR) {
  798.             rip(buf);
  799.             getsub(ftp, "RETR", buf, buf);
  800.  
  801.             if (ftp->abort) {                                /* user abort                    */
  802.                 ftp->abort = 0;
  803.                 fclose(files);
  804.                 unlink(tmpname);
  805.                 free(buf);
  806.                 ftp->state = COMMAND_STATE;
  807.                 return 1;
  808.             }
  809.         }
  810.         fclose(files);
  811.         unlink(tmpname);
  812.     }
  813.  
  814.     free(buf);
  815.     ftp->state = COMMAND_STATE;
  816.     ftp->abort = 0;
  817.     return 0;
  818. }
  819.  
  820.  
  821. /*
  822.     dolist - List remote directory. Syntax: dir <remote files> [<local name>]
  823. */
  824.  
  825. static int dolist(int argc, char *argv[], void *p)
  826. {
  827.     char *remotename,*localname;
  828.     register struct ftpcli *ftp;
  829.  
  830.     ftp = (struct ftpcli *)p;
  831.     if(ftp == NULLFTP){
  832.         tprintf(Notsess);
  833.         return 1;
  834.     }
  835.     remotename = argv[1];
  836.     if(argc > 2)
  837.         localname = argv[2];
  838.     else
  839.         localname = NULLCHAR;
  840.  
  841.     getsub(ftp,"LIST",remotename,localname);
  842.     return 0;
  843. }
  844. /* Remote directory list, short form. Syntax: ls <remote files> [<local name>] */
  845. static int
  846. dols(argc,argv,p)
  847. int argc;
  848. char *argv[];
  849. void *p;
  850. {
  851.     char *remotename,*localname;
  852.     register struct ftpcli *ftp;
  853.  
  854.     ftp = (struct ftpcli *)p;
  855.     if(ftp == NULLFTP){
  856.         tprintf(Notsess);
  857.         return 1;
  858.     }
  859.     remotename = argv[1];
  860.     if(argc > 2)
  861.         localname = argv[2];
  862.     else
  863.         localname = NULLCHAR;
  864.  
  865.     getsub(ftp,"NLST",remotename,localname);
  866.     return 0;
  867. }
  868.  
  869.  
  870. /*
  871.     getsub - Common code to LIST/NLST/RETR and mget
  872.                 Returns number of bytes received if successful
  873.                 Returns -1 on error
  874. */
  875.  
  876. static long getsub(struct ftpcli *ftp,
  877.                          char *command,
  878.                           char *remotename,
  879.                           char *localname
  880.                        )
  881. {
  882.     unsigned long total;
  883.     FILE *fp;
  884.     int cnt,resp,i,control,savmode;
  885.     char *mode;
  886.     struct sockaddr_in lsocket;
  887.     struct sockaddr_in lcsocket;
  888.     int32 startclk,rate;
  889.     int vsave;
  890.     int typewait = 0;
  891.     int prevstate;
  892.  
  893.     if (ftp == NULLFTP)
  894.         return -1;
  895.         
  896.     control = ftp->control;
  897.     savmode = ftp->type;
  898.  
  899.     switch (ftp->type) {
  900.     case IMAGE_TYPE:
  901.     case LOGICAL_TYPE:
  902.         mode = WRITE_BINARY;
  903.         break;
  904.     case ASCII_TYPE:
  905.         mode = WRITE_TEXT;
  906.         break;
  907.     }
  908.  
  909.     if (localname == NULLCHAR) {                    /* open the file                    */
  910.         fp = NULLFILE;
  911.     } else
  912.         if ((fp = fopen(localname, mode)) == NULLFILE) {
  913.             tprintf("Can't write %s: %s\n", localname, strerror(errno));
  914.         return -1;
  915.     }
  916.     
  917.     /* Open the data connection */
  918.  
  919.     ftp->data = socket(AF_INET, SOCK_STREAM, 0);
  920.     listen(ftp->data,0);                                /* Accept only one connection */
  921.     prevstate = ftp->state;
  922.     ftp->state = RECEIVING_STATE;
  923.  
  924.     /* Send TYPE message, if necessary */
  925.     
  926.    if (strcmp(command, "LIST") == 0 ||
  927.              strcmp(command, "NLST") == 0 ||
  928.              (fp == NULLFILE)
  929.         )  {
  930.  
  931.         /* Directory listings are always in ASCII */
  932.  
  933.         ftp->type = ASCII_TYPE;
  934.     }
  935.  
  936.     if (ftp->typesent != ftp->type) {
  937.         switch (ftp->type) {
  938.         case ASCII_TYPE:
  939.             usprintf(control, "TYPE A\n");
  940.             break;
  941.         case IMAGE_TYPE:
  942.             usprintf(control, "TYPE I\n");
  943.             break;
  944.         case LOGICAL_TYPE:
  945.             usprintf(control, "TYPE L %d\n", ftp->logbsize);
  946.             break;
  947.         }
  948.         
  949.         ftp->typesent = ftp->type;
  950.  
  951.         if (!ftp->batch) {
  952.             resp = getresp(ftp, 200);
  953.             if (resp == -1 || resp > 299)
  954.                 goto failure;
  955.         } else
  956.             typewait = 1;
  957.     }
  958.     
  959.     /*
  960.         Send the PORT message. Use the IP address
  961.          on the local end of our control connection.
  962.     */
  963.  
  964.     i = SOCKSIZE;
  965.     getsockname(ftp->data, (char *)&lsocket,&i);     /* Get port number         */
  966.     i = SOCKSIZE;
  967.     getsockname(ftp->control, (char *)&lcsocket, &i);
  968.     lsocket.sin_addr.s_addr = lcsocket.sin_addr.s_addr;
  969.     sendport(control, &lsocket);
  970.     
  971.     if (!ftp->batch) {
  972.         
  973.         /* Get response to PORT command */
  974.  
  975.         resp = getresp(ftp,200);
  976.         if (resp == -1 || resp > 299)
  977.             goto failure;
  978.     }
  979.     
  980.     /*** Generate the command to start the transfer ***/
  981.  
  982.     if (remotename != NULLCHAR)
  983.         usprintf(control,"%s %s\n", command, remotename);
  984.     else
  985.         usprintf(control,"%s\n", command);
  986.  
  987.     if (ftp->batch) {
  988.         
  989.         /*** Get response to TYPE command, if sent ***/
  990.  
  991.         if (typewait) {
  992.             resp = getresp(ftp, 200);
  993.             if (resp == -1 || resp > 299)
  994.                 goto failure;
  995.         }
  996.         
  997.         /* Get response to PORT command */
  998.  
  999.         resp = getresp(ftp,200);
  1000.  
  1001.         if (resp == -1 || resp > 299)
  1002.             goto failure;
  1003.     }
  1004.     
  1005.     /* Get the intermediate "150" response */
  1006.  
  1007.     resp = getresp(ftp,100);
  1008.  
  1009.     if (resp == -1 || resp >= 400)
  1010.         goto failure;
  1011.  
  1012.     /* Wait for the server to open the data connection */
  1013.  
  1014.     cnt = 0;
  1015.     ftp->data = accept(ftp->data, NULLCHAR, &cnt);
  1016.     startclk = msclock();
  1017.  
  1018.     /* If output is to the screen, temporarily disable hash marking */
  1019.     
  1020.     vsave = ftp->verbose;
  1021.     if (vsave >= V_HASH && fp == NULLFILE)
  1022.         ftp->verbose = V_NORMAL;
  1023.         
  1024. #ifndef ATARI        
  1025.     total = recvfile(fp, ftp->data, ftp->type, ftp->verbose >= V_HASH, ftp->wrap);
  1026. #else
  1027.       total = recvfile(fp,ftp->data,ftp->type,
  1028.                           (ftp->verbose >= V_HASH) ? ftp->verbose : 0, ftp->wrap);        
  1029. #endif
  1030.  
  1031.     /*
  1032.         Immediately close the data connection; some servers (e.g., TOPS-10)
  1033.          wait for the data connection to close completely before returning
  1034.          the completion message on the control channel
  1035.     */
  1036.     
  1037.     close_s(ftp->data);
  1038.     ftp->data = -1;
  1039.  
  1040.     if (fp != NULLFILE && fp != stdout)
  1041.         fclose(fp);
  1042.  
  1043.     if (remotename == NULLCHAR)
  1044.         remotename = "";
  1045.         
  1046.     if (total == -1) {
  1047.         tprintf("%s %s: Error/abort during data transfer\n", command, remotename);
  1048.     } else
  1049.         if (ftp->verbose >= V_SHORT) {
  1050.             startclk = msclock() - startclk;
  1051.             rate = 0;
  1052.         if    (startclk != 0)    {                        /* Avoid divide-by-zero         */
  1053.             if (total < 4294967L) {
  1054.                 rate = (total*1000) / startclk;
  1055.             } else {                                        /* Avoid overflow                 */
  1056.                 rate = total/(startclk/1000);
  1057.             }
  1058.         }
  1059.         
  1060.         tprintf("%s %s: %lu bytes in %lu sec (%lu/sec)\n",
  1061.                      command, remotename, total, startclk/1000, rate);
  1062.     }
  1063.     
  1064.     /* Get the "Sent" message */
  1065.  
  1066.     getresp(ftp, 200);
  1067.  
  1068.     ftp->state         = prevstate;
  1069.     ftp->verbose     = vsave;
  1070.     ftp->type         = savmode;
  1071.     
  1072.     log(ftp->control, "FTP %s: %s remote: %s local: %s",
  1073.          ftp->session->name, command, remotename, localname);
  1074.     return total;
  1075.  
  1076. failure:
  1077.  
  1078.     /* Error, quit */
  1079.  
  1080.     if (fp != NULLFILE && fp != stdout)
  1081.         fclose(fp);
  1082.         
  1083.     close_s(ftp->data);
  1084.     
  1085.     ftp->data  = -1;
  1086.     ftp->state = prevstate;
  1087.     ftp->type  = savmode;
  1088.  
  1089.     log(ftp->control, "FTP failed %s: %s remote %s local %s\n",
  1090.          ftp->session->name, command, remotename, localname);
  1091.     return -1;
  1092. }
  1093.  
  1094. /* Send a file. Syntax: put <local name> [<remote name>] */
  1095. static int
  1096. doput(argc,argv,p)
  1097. int argc;
  1098. char *argv[];
  1099. void *p;
  1100. {
  1101.     register struct ftpcli *ftp;
  1102.     char *remotename,*localname;
  1103.  
  1104.     if((ftp = (struct ftpcli *)p) == NULLFTP){
  1105.         tprintf(Notsess);
  1106.         return 1;
  1107.     }
  1108.     localname = argv[1];
  1109.     if(argc < 3)
  1110.         remotename = localname;
  1111.     else
  1112.         remotename = argv[2];
  1113.  
  1114.     putsub(ftp,remotename,localname);
  1115.     return 0;
  1116. }
  1117. /* Put a collection of files */
  1118. static int
  1119. domput(argc,argv,p)
  1120. int argc;
  1121. char *argv[];
  1122. void *p;
  1123. {
  1124.     register struct ftpcli *ftp;
  1125.     FILE *files;
  1126.     int i;
  1127.     char tmpname[L_tmpnam+1];
  1128.     char *buf;
  1129.  
  1130.     if((ftp = (struct ftpcli *)p) == NULLFTP){
  1131.         tprintf(Notsess);
  1132.         return 1;
  1133.     }
  1134.     tmpnam(tmpname);
  1135.     if((files = fopen(tmpname,"w+")) == NULLFILE){
  1136.         tprintf("Can't list local files\n");
  1137.         unlink(tmpname);
  1138.         return 1;
  1139.     }
  1140.     for(i=1;i<argc;i++)
  1141.         getdir(argv[i],0,files);
  1142.  
  1143.     rewind(files);
  1144.     buf = mallocw(DIRBUF);
  1145.     ftp->state = SENDING_STATE;
  1146.     while(fgets(buf,DIRBUF,files) != NULLCHAR){
  1147.         rip(buf);
  1148.         putsub(ftp,buf,buf);
  1149.         if(ftp->abort)
  1150.             break;        /* User abort */
  1151.     }
  1152.     fclose(files);
  1153.     unlink(tmpname);
  1154.     free(buf);
  1155.     ftp->state = COMMAND_STATE;
  1156.     ftp->abort = 0;
  1157.     return 0;
  1158. }
  1159. /* Common code to put, mput.
  1160.  * Returns number of bytes sent if successful
  1161.  * Returns -1 on error
  1162.  */
  1163. static long
  1164. putsub(ftp,remotename,localname)
  1165. register struct ftpcli *ftp;
  1166. char *remotename,*localname;
  1167. {
  1168.     char *mode;
  1169.     int i,resp,control;
  1170.     unsigned long total;
  1171.     FILE *fp;
  1172.     struct sockaddr_in lsocket,lcsocket;
  1173.     int32 startclk,rate;
  1174.     int typewait = 0;
  1175.     int prevstate;
  1176.  
  1177.     control = ftp->control;
  1178.     if(ftp->type == IMAGE_TYPE)
  1179.         mode = READ_BINARY;
  1180.     else
  1181.         mode = READ_TEXT;
  1182.  
  1183.     /* Open the file */
  1184.     if((fp = fopen(localname,mode)) == NULLFILE){
  1185.         tprintf("Can't read %s: %s\n",localname,strerror(errno));
  1186.         return -1;
  1187.     }
  1188.     if(ftp->type == ASCII_TYPE && isbinary(fp)){
  1189.         tprintf("Warning: type is ASCII and %s appears to be binary\n",localname);
  1190.     }
  1191.     /* Open the data connection */
  1192.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  1193.     listen(ftp->data,0);
  1194.     prevstate = ftp->state;
  1195.     ftp->state = SENDING_STATE;
  1196.  
  1197.     /* Send TYPE message, if necessary */
  1198.     if(ftp->typesent != ftp->type){
  1199.         switch(ftp->type){
  1200.         case ASCII_TYPE:
  1201.             usprintf(control,"TYPE A\n");
  1202.             break;
  1203.         case IMAGE_TYPE:
  1204.             usprintf(control,"TYPE I\n");
  1205.             break;
  1206.         case LOGICAL_TYPE:
  1207.             usprintf(control,"TYPE L %d\n",ftp->logbsize);
  1208.             break;
  1209.         }
  1210.         ftp->typesent = ftp->type;
  1211.  
  1212.         /* Get response to TYPE command */
  1213.         if(!ftp->batch){
  1214.             resp = getresp(ftp,200);
  1215.             if(resp == -1 || resp > 299){
  1216.                 goto failure;
  1217.             }
  1218.         } else
  1219.             typewait = 1;
  1220.     }
  1221.     /* Send the PORT message. Use the IP address
  1222.      * on the local end of our control connection.
  1223.      */
  1224.     i = SOCKSIZE;
  1225.     getsockname(ftp->data,(char *)&lsocket,&i);
  1226.     i = SOCKSIZE;
  1227.     getsockname(ftp->control,(char *)&lcsocket,&i);
  1228.     lsocket.sin_addr.s_addr = lcsocket.sin_addr.s_addr;
  1229.     sendport(control,&lsocket);
  1230.     if(!ftp->batch){
  1231.         /* Get response to PORT command */
  1232.         resp = getresp(ftp,200);
  1233.         if(resp == -1 || resp > 299){
  1234.             goto failure;
  1235.         }
  1236.     }
  1237.     /* Generate the command to start the transfer */
  1238.     usprintf(control,"STOR %s\n",remotename);
  1239.  
  1240.     if(ftp->batch){
  1241.         /* Get response to TYPE command, if sent */
  1242.         if(typewait){
  1243.             resp = getresp(ftp,200);
  1244.             if(resp == -1 || resp > 299){
  1245.                 goto failure;
  1246.             }
  1247.         }
  1248.         /* Get response to PORT command */
  1249.         resp = getresp(ftp,200);
  1250.         if(resp == -1 || resp > 299){
  1251.             goto failure;
  1252.         }
  1253.     }
  1254.     /* Get the intermediate "150" response */
  1255.     resp = getresp(ftp,100);
  1256.     if(resp == -1 || resp >= 400){
  1257.         goto failure;
  1258.     }
  1259.  
  1260.     /* Wait for the data connection to open. Otherwise the first
  1261.      * block of data would go out with the SYN, and this may confuse
  1262.      * some other TCPs
  1263.      */
  1264.     accept(ftp->data,NULLCHAR,(int *)NULL);
  1265.  
  1266.     startclk = msclock();
  1267.  
  1268. #ifndef ATARI     
  1269.     total = sendfile (fp,ftp->data,ftp->type,ftp->verbose >= V_HASH, ftp->wrap);
  1270. #else
  1271.  
  1272.     total = sendfile(fp,ftp->data,ftp->type,
  1273.                           (ftp->verbose >= V_HASH) ? ftp->verbose : 0, ftp->wrap);
  1274. #endif
  1275.     
  1276.     close_s(ftp->data);
  1277.     ftp->data = -1;
  1278.     fclose(fp);
  1279.  
  1280.     /* Wait for control channel ack before calculating transfer time;
  1281.      * this accounts for transmitted data in the pipe
  1282.      */
  1283.     getresp(ftp,200);
  1284.  
  1285.     if(total == -1){
  1286.         tprintf("STOR %s: Error/abort during data transfer\n",remotename);
  1287.     } else if(ftp->verbose >= V_SHORT){
  1288.         startclk = msclock() - startclk;
  1289.         rate = 0;
  1290.         if(startclk != 0){    /* Avoid divide-by-zero */
  1291.             if(total < 4294967L) {
  1292.                 rate = (total*1000)/startclk;
  1293.             } else {    /* Avoid overflow */
  1294.                 rate = total/(startclk/1000);
  1295.             }
  1296.         }
  1297.         tprintf("STOR %s: %lu bytes in %lu sec (%lu/sec)\n",
  1298.          remotename,total,startclk/1000,rate);
  1299.     }
  1300.     ftp->state = prevstate;
  1301.     return total;
  1302.  
  1303. failure:
  1304.     /* Error, quit */
  1305.     fclose(fp);
  1306.     close_s(ftp->data);
  1307.     ftp->data = -1;
  1308.     ftp->state = prevstate;
  1309.     return -1;
  1310. }
  1311. /* Abort a GET or PUT operation in progress. Note: this will leave
  1312.  * the partial file on the local or remote system
  1313.  */
  1314. int
  1315. doabort(argc,argv,p)
  1316. int argc;
  1317. char *argv[];
  1318. void *p;
  1319. {
  1320.     register struct session *sp;
  1321.     register struct ftpcli *ftp;
  1322.  
  1323.     sp = (struct session *)p;
  1324.     if(sp == NULLSESSION)
  1325.         return -1;
  1326.  
  1327.     /* Default is the current session, but it can be overridden with
  1328.      * an argument.
  1329.      */
  1330.     if(argc > 1)
  1331.         sp = sessptr(argv[1]);
  1332.  
  1333.     if(sp == NULLSESSION || sp->type != FTP){
  1334.         tprintf("Not an active FTP session\n");
  1335.         return 1;
  1336.     }
  1337.     ftp = sp->cb.ftp;
  1338.     switch(ftp->state){
  1339.     case COMMAND_STATE:
  1340.         tprintf("No active transfer\n");
  1341.         return 1;
  1342.     case SENDING_STATE:
  1343.         /* Send a premature EOF.
  1344.          * Unfortunately we can't just reset the connection
  1345.          * since the remote side might end up waiting forever
  1346.          * for us to send something.
  1347.          */
  1348.         shutdown(ftp->data,1);    /* Note fall-thru */
  1349.         ftp->abort = 1;
  1350.         break;
  1351.     case RECEIVING_STATE:
  1352.         /* Just blow away the receive socket */
  1353.         shutdown(ftp->data,2);    /* Note fall-thru */
  1354.         ftp->abort = 1;
  1355.         break;
  1356.     }
  1357.     return 0;
  1358. }
  1359. /* send PORT message */
  1360. static void
  1361. sendport(s,socket)
  1362. int s;
  1363. struct sockaddr_in *socket;
  1364. {
  1365.     /* Send PORT a,a,a,a,p,p message */
  1366.     usprintf(s,"PORT %u,%u,%u,%u,%u,%u\n",
  1367.         hibyte(hiword(socket->sin_addr.s_addr)),
  1368.         lobyte(hiword(socket->sin_addr.s_addr)),
  1369.         hibyte(loword(socket->sin_addr.s_addr)),
  1370.         lobyte(loword(socket->sin_addr.s_addr)),
  1371.         hibyte(socket->sin_port),
  1372.         lobyte(socket->sin_port));
  1373. }
  1374.  
  1375. /* Wait for, read and display response from FTP server. Return the result code.
  1376.  */
  1377. static int
  1378. getresp(ftp,mincode)
  1379. struct ftpcli *ftp;
  1380. int mincode;    /* Keep reading until at least this code comes back */
  1381. {
  1382.     register char *line;
  1383.     int rval;
  1384.  
  1385.     usflush(ftp->control);
  1386.     line = mallocw(LINELEN);
  1387.     for(;;){
  1388.         /* Get line */
  1389.         if(recvline(ftp->control,line,LINELEN) == -1){
  1390.             rval = -1;
  1391.             break;
  1392.         }
  1393.         rip(line);        /* Remove cr/lf */
  1394.         rval = atoi(line);
  1395.         if(rval >= 400 || ftp->verbose >= V_NORMAL)
  1396.             tprintf("%s\n",line);    /* Display to user */
  1397.  
  1398.         /* Messages with dashes are continued */
  1399.         if(line[3] != '-' && rval >= mincode)
  1400.             break;
  1401.     }
  1402.     free(line);
  1403.     return rval;
  1404. }
  1405.  
  1406. /* Issue a prompt and read a line from the user */
  1407. static int
  1408. getline(sp,prompt,buf,n)
  1409. struct session *sp;
  1410. char *prompt;
  1411. char *buf;
  1412. int n;
  1413. {
  1414.     /* If there's something already there, don't issue prompt */
  1415.     if(socklen(sp->input,0) == 0)
  1416.         tprintf(prompt);
  1417.  
  1418.     usflush(sp->output);
  1419.     return recvline(sp->input,buf,n);
  1420. }
  1421.  
  1422. static int dosource(int argc,char *argv[],void *p)
  1423.      {
  1424.     register struct ftpcli *ftp;
  1425.  
  1426.         if((ftp = (struct ftpcli *)p) == NULLFTP)
  1427.                 return -1;
  1428.  
  1429.         /* test for sourcing fom a file within a sourced file */
  1430.         if(ftp->sourcefileon==1)
  1431.              {
  1432.                 tprintf("Already sourcing commands from file\n");
  1433.                 return -1;
  1434.              }
  1435.  
  1436.         if((ftp->source=fopen(argv[1],"r"))==NULL) {
  1437.              char tmpbuf[255];
  1438.                  sprintf(tmpbuf, "%s\\%s\0", Dscripts, argv[1]);  /* try script dir */
  1439.  
  1440.              if ((ftp->source = fopen(tmpbuf, "r")) == NULL) {
  1441.                 tprintf("Unable to open file %s\n",argv[1]);
  1442.                 return -1;
  1443.             }
  1444.          }
  1445.         /* flag sourcing commands from file */
  1446.         ftp->sourcefileon=1;
  1447.         return 1;
  1448.      }
  1449.  
  1450. static void sourceline(struct session *sp,char *prompt,char *buf,int n)
  1451.      {
  1452.  
  1453.       register struct ftpcli *ftp;
  1454.  
  1455.       if((ftp = (struct ftpcli *)sp->cb.ftp) == NULLFTP)
  1456.                 return;
  1457.  
  1458.         /* set pager mode to off, if it's on */
  1459.  
  1460.         if(sp->flowmode==1)
  1461.                 sp->flowmode=0;
  1462.  
  1463.         /* read a line from the script file, if fgets returns a NULL then
  1464.              assume that EOF has been reached and act accordingly */
  1465.  
  1466.         if((fgets(buf,n,ftp->source))==NULL)
  1467.              {
  1468.                 ftp->sourcefileon=0;
  1469.                 fclose(ftp->source);
  1470.                 *buf=0;
  1471.              }
  1472.         else
  1473.              {
  1474.                 /* check line contains a "\n" as the command may fail if not
  1475.                      as might the next as well */
  1476.  
  1477.                 if((strstr(buf,"\n"))==NULL)
  1478.                      tprintf("The following command may fail, line possibly too long\n");
  1479.  
  1480.                 if(sp->ttystate.echo != 0)
  1481.                     tprintf("%s %s\n",prompt,buf);
  1482.                 else
  1483.                     tprintf("%s",prompt);
  1484.  
  1485.              }
  1486.      }
  1487.  
  1488.  
  1489. static int doopen (int argc, char *argv[], void *p)
  1490.    {
  1491.      int control =-1 ;
  1492.      int resp;
  1493.  
  1494.      struct ftpcli  *ftp;
  1495.      struct session *sp;
  1496.      struct sockaddr_in *fsocket;
  1497.  
  1498.      ftp = (struct ftpcli *)p;
  1499.      sp = (struct session *)ftp->session;
  1500.      fsocket = (struct sockaddr_in *)ftp->fsocket;
  1501.  
  1502.      if((ftp->control != -1) && (ftp->control != -2))
  1503.        {
  1504.         tprintf("You must close the current connection before opening another\n");
  1505.         return 200;
  1506.        }
  1507.  
  1508.     if(strcmp(sp->name,dummyhost)==0)
  1509.        {
  1510.          free(sp->name);
  1511.          sp->name=strdup (argv[1]);
  1512.        }
  1513.  
  1514.     if(argc < 3)
  1515.         fsocket->sin_port = IPPORT_FTP;
  1516.     else
  1517.         fsocket->sin_port = atoi(argv[2]);
  1518.     tprintf("Resolving %s... ",sp->name);
  1519.  
  1520.     if((fsocket->sin_addr.s_addr = resolve(sp->name)) == 0){
  1521.         tprintf(Badhost,sp->name);
  1522.         keywait(NULLCHAR,1);
  1523.         free(sp->name);
  1524.         sp->name=strdup(dummyhost);
  1525.         return 200;
  1526.     }
  1527.  
  1528.     /* Open the control connection */
  1529.     if((control = sp->s = ftp->control = socket(AF_INET,SOCK_STREAM,0)) == -1){
  1530.         tprintf("Can't create socket\n");
  1531.         keywait(NULLCHAR,1);
  1532.             free(sp->name);
  1533.         sp->name=strdup(dummyhost);
  1534.         return 1;
  1535.     }
  1536.  
  1537.     sockmode(sp->s,SOCK_ASCII);
  1538.     setflush(sp->s,-1);    /* Flush output only when we call getresp() */
  1539.     tprintf("Trying %s...\n",psocket((struct sockaddr *)fsocket));
  1540.     if(connect(control,(char *)fsocket,sizeof(struct sockaddr_in)) == -1)
  1541.        {
  1542.         tprintf ("FTP Session %u unable to conect to %s\n",(unsigned)(sp-Sessions),
  1543.               sp->name);
  1544.         ftp->control=ftp->data=NOTCONNECTED;
  1545.         return 200;
  1546.        }
  1547.  
  1548.     tprintf("FTP session %u connected to %s\n",(unsigned)(sp-Sessions),
  1549.         sp->name);
  1550.  
  1551.     /* Wait for greeting from server */
  1552.     resp = getresp(ftp,200);
  1553.     return resp;
  1554.    }
  1555.  
  1556.  
  1557. static int doclose ( int argc, char *argv[], void *p)
  1558.    {
  1559.     struct ftpcli *ftp;
  1560.     ftp=(struct ftpcli*)p;
  1561.     if((ftp->control == -2) || (ftp->control == -1))
  1562.        {
  1563.         tprintf("You must open a connection before attempting to close it\n");
  1564.         return 200;
  1565.        }
  1566.  
  1567.     usprintf(ftp->control,"QUIT\n");
  1568.     getresp(ftp,200);    /* Get the closing message */
  1569.     getresp(ftp,200);    /* Wait for the server to close */
  1570.  
  1571.     if(ftp->fp != NULLFILE && ftp->fp != stdout)
  1572.         fclose(ftp->fp);
  1573.     if(ftp->data != -1)
  1574.         close_s(ftp->data);
  1575.     if(ftp->control != -1)
  1576.         close_s(ftp->control);
  1577.  
  1578.     ftp->control=ftp->data=NOTCONNECTED;
  1579.     free(ftp->session->name);
  1580.     ftp->session->name=strdup(dummyhost);
  1581.     set_default_opts (ftp);                /* reset defaults                    */
  1582.     return 200;
  1583.    }
  1584.  
  1585. static void init_ftpstruct(struct session *sp,struct ftpcli *ftp,
  1586.                   struct sockaddr_in *fsocket)
  1587.    {
  1588.      memset((char *)ftp,0,sizeof(struct ftpcli));
  1589.      ftp->control = ftp->data = NOTCONNECTED;
  1590.      sp->cb.ftp = ftp;    /* Downward link */
  1591.      ftp->session = sp;    /* Upward link */
  1592.      ftp->fsocket = fsocket;  /* to help with doopen */
  1593.      fsocket->sin_family = AF_INET;
  1594.      set_default_opts (ftp);
  1595.    }
  1596.  
  1597.  
  1598. /****************************************************************************
  1599. *    set_default_opts                                                        *
  1600. *    Set session default options from persistent defaults set by "ftpopt".    *
  1601. ****************************************************************************/
  1602.  
  1603. static void set_default_opts (ftp)
  1604. struct ftpcli *ftp;
  1605.     {
  1606.     ftp->verbose = verbose;
  1607.     ftp->typesent = 0;
  1608.     ftp->type = type;
  1609.     ftp->logbsize = logbsize;
  1610.     ftp->wrap = wrap;
  1611.     ftp->session->flowmode = pager;
  1612.     }    /* static void set_default_opts (ftp) */
  1613.